package virtPresenter.model
{
	import com.adobe.cairngorm.control.CairngormEventDispatcher;
	
	import flash.display.DisplayObject;
	import flash.display.Loader;
	import flash.display.MovieClip;
	import flash.display.SpreadMethod;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.net.URLRequest;
	
	import virtPresenter.event.MainWindowMiniPreviewEvent;
	import virtPresenter.control.virtPresenterController;

	/**
	 * This class is responsible for loading mini-images in order to complete the fish-eye-effect.
	 * 
	 * @author: Sebastian Pospiech
	 */
	public class MiniPreview
	{
		//Array of Display objects
		private static var images:Array; 
		private var locator:virtPresenterLocator = virtPresenterLocator.getInstance();
		private var slides:Array = locator.xmlParser.getSlides();
		
		private var imageLoader:Loader;
		private var preLoadingComplete:Boolean = false;
		private var loadCounter:int;
		
		public function MiniPreview()
		{
			loadImages(0);
		}
		
		/**
		 * Loads the content into the images array
		 * 
		 * @param: i Current slide Index of slide that is loaded
		 */
		public function loadImages(i:int):void{
			if (i == 0) {
				resetSlides();
				images = new Array();
			}
			var path:
			String = "lectures/"
				+ locator.lectureFolder
				+ "/assets/img/";
			this.loadCounter = i;
			var tmp:TimeStep = slides[i];
			var pathToMini:String = path + "slide"+tmp.getID()+".jpg";
			imageLoader = new Loader();
			imageLoader.contentLoaderInfo.addEventListener(Event.COMPLETE,onComplete);
			var imageRequest:URLRequest = new URLRequest(pathToMini);
			imageLoader.load(imageRequest);
		}
		
		/**
		 * Handler for the onCompleteEvent of the imageLoader
		 * Sets parameters for the MovieClips the handle the iamge files
		 * and initiates loading of the next image.
		 * 
		 * @param: Event
		 */
		private function onComplete(evt:Event):void{
			var dO:MovieClip = new MovieClip();
			dO.addChild(imageLoader);
			dO.useHandCursor = false;
			dO.visible = false;
			dO.addEventListener(MouseEvent.CLICK, onClick);
			dO.addEventListener(MouseEvent.MOUSE_OVER, onMouseOver);
			dO.addEventListener(MouseEvent.MOUSE_OUT, onMouseOut);
			locator.scrubber.addChild(dO);
			images.push(dO);
			if (loadCounter<slides.length-1) {	
				loadImages(this.loadCounter+1);
			}
			else{
				preLoadingComplete = true;
			}
		}
		
		/**
		 * Handler for the mouseOver Event of a Mini Preview Image. 
		 * Invokes a preview of the slide.
		 *
		 * @param: Event
		 */
		private function onMouseOver(evt:Event):void{
			trace("mouseover");
			var slideArrayIndex:int = getSlideNumber(Loader(evt.target));
			var currSlide:TimeStep = slides[slideArrayIndex];
			CairngormEventDispatcher.getInstance().dispatchEvent(new MainWindowMiniPreviewEvent(currSlide.getID()));
		}
		
		/**
		 * Handler for the mouseOut Event of a Mini Preview Image. 
		 * Resets the slide to the current one.
		 *
		 * @param: Event
		 */
		private function onMouseOut(evt:Event):void{
			CairngormEventDispatcher.getInstance().dispatchEvent(new MainWindowMiniPreviewEvent(-1));
		}
		
		/**
		 * Handler for the onClick Event of a Mini Preview Image. 
		 * Invokes a time jump to the slide, where the click was executed on.
		 *
		 * @param: Event
		 */
		private function onClick(evt:Event):void{
			var slideArrayIndex:int = getSlideNumber(Loader(evt.target));
			var currSlide:TimeStep = slides[slideArrayIndex];
			locator.scrubber.changeVideoPosition(currSlide.getTime()/1000);
		}
		
		/**
		 * Gets the Index of a slide for a certain image object
		 * 
		 * @param: Loader of the image.
		 */
		private function getSlideNumber(o:Loader):int{
			for(var i:int = 0;i<images.length;i++){
				if (MovieClip(images[i]) == o.parent)
					return i;
			}
			return -1;
		}
		
		/**
		 * makes all images invisible
		 */
		private function resetSlides():void{
			if (images == null) return;
			for(var i:int=0;i<images.length;i++){
				MovieClip(images[i]).visible = false;
			}	
		}
		
		/**
		 * Show the mini slides.
		 * 
		 * @param: leftIsVisible: true if left side should be visible, else false)
		 * @param: rightIsVisible: true if right side should be visible, else false)
		 */
		public function showMiniSlides(leftIsVisible:Boolean, rightIsVisible:Boolean, parentObject:Sprite, currentX:int):void{
			if (!preLoadingComplete) return;
			resetSlides();
			var slideArrayIndex:int = getSlideArrayIndex();
			if (leftIsVisible) showPreviousSlides(parentObject, currentX, slideArrayIndex);
			if (rightIsVisible)showNextSlides(parentObject, currentX,slideArrayIndex);
		}
		
		private function getSlideArrayIndex():int{
			var slideArrayIndex:int = 0;
			var tmp:TimeStep = slides[slideArrayIndex];
			if (locator.currentSlideID == 0) return 1; //crappy
			while (tmp.getID()!=locator.currentSlideID){
				slideArrayIndex++;
				tmp = slides[slideArrayIndex];
			}
			return slideArrayIndex;
		}
		
		private function showPreviousSlides(sprite:Sprite, currentX:int, slideArrayIndex:int):void{
			var numbOfSlides:int = slideArrayIndex;
			
			var xCoordinate:int = currentX-AS_Constants.WIDTH_PREVIEW_MIDDLE/2
				- AS_Constants.WIDTH_PREVIEW_SIDES
				- AS_Constants.WIDTH_MINI_PREVIEW
				- locator.scrubber.calculatePreviewPosition()
				-2;
			var tmp:DisplayObject = images[slideArrayIndex-1];
			if (tmp==null) return;
			tmp.height = AS_Constants.HEIGHT_MINI_PREVIEW+1;
			tmp.width = AS_Constants.WIDTH_MINI_PREVIEW;
			tmp.y = AS_Constants.SCRUBBER_HEIGHT //seems to be wrong...
				+AS_Constants.DISTANCE_PREVIEW_SIDES_TO_SCRUBBER
				+AS_Constants.HEIGHT_PREVIEW_SIDES
				-AS_Constants.HEIGHT_MINI_PREVIEW*2
				-2;
			
			tmp.x = xCoordinate;
			tmp.visible = true;
			
			var availableWidth:int = AS_Constants.WIDTH_PREVIEW_SIDES*(2/3) - AS_Constants.WIDTH_MINI_PREVIEW;
			var numOfRowsFound:Boolean = false;
			var numOfRows:int = 0;
			var slidesPerRow:int;
			var restHeight:int;
			var restWidth:int;
			while (!numOfRowsFound){
				numOfRows++;
				restHeight = (AS_Constants.HEIGHT_MINI_PREVIEW-2) / numOfRows;
				restWidth = restHeight * (4/3);
				slidesPerRow = (availableWidth / (restWidth+1));
				var capacity: int = slidesPerRow*numOfRows;
				if (capacity>=numbOfSlides-1)
					numOfRowsFound = true;
			}
			var slideToProcess:int = slideArrayIndex-2;
			for (var i:int=1;i<=numOfRows;i++){
				xCoordinate = currentX-AS_Constants.WIDTH_PREVIEW_MIDDLE/2
					- AS_Constants.WIDTH_PREVIEW_SIDES
					- AS_Constants.WIDTH_MINI_PREVIEW
					- 2
					- restWidth -1
					- locator.scrubber.calculatePreviewPosition();
				var yCoordinate:int = AS_Constants.SCRUBBER_HEIGHT
					+AS_Constants.DISTANCE_PREVIEW_SIDES_TO_SCRUBBER
					+AS_Constants.HEIGHT_PREVIEW_SIDES
					-30-(restHeight+1)*i;
				for (var j:int=1;j<=slidesPerRow;j++){
					if (slideToProcess < 0) return;
					tmp = images[slideToProcess];
					tmp.height = restHeight;
					tmp.width = restWidth;
					tmp.x = xCoordinate;
					tmp.y = yCoordinate;
					xCoordinate = xCoordinate - restWidth -1;
					tmp.visible = true;
					slideToProcess-=1;
				}
			}
		}
		
		private function showNextSlides(sprite:Sprite, currentX:int, slideArrayIndex:int):void{	
			var numbOfSlides:int = slides.length-slideArrayIndex;
			
			var xCoordinate:int = currentX
				+ AS_Constants.WIDTH_PREVIEW_MIDDLE/2
				+ AS_Constants.WIDTH_PREVIEW_SIDES
				- locator.scrubber.calculatePreviewPosition()
				+ 2;
			var tmp:DisplayObject = images[slideArrayIndex+1];
			if (tmp==null) return;
			tmp.height = AS_Constants.HEIGHT_MINI_PREVIEW+1;
			tmp.width = AS_Constants.WIDTH_MINI_PREVIEW;
			tmp.y = AS_Constants.SCRUBBER_HEIGHT //seems to be wrong...
				+AS_Constants.DISTANCE_PREVIEW_SIDES_TO_SCRUBBER
				+AS_Constants.HEIGHT_PREVIEW_SIDES
				-AS_Constants.HEIGHT_MINI_PREVIEW*2
				-2;
			
			tmp.x = xCoordinate;
			tmp.visible = true;
			
			var availableWidth:int = AS_Constants.WIDTH_PREVIEW_SIDES*(2/3) - AS_Constants.WIDTH_MINI_PREVIEW;
			var numOfRowsFound:Boolean = false;
			var numOfRows:int = 0;
			var slidesPerRow:int;
			var restHeight:int;
			var restWidth:int;
			while (!numOfRowsFound){
				numOfRows++;
				restHeight = (AS_Constants.HEIGHT_MINI_PREVIEW-2) / numOfRows;
				restWidth = restHeight * (4/3);
				slidesPerRow = (availableWidth / (restWidth+1));
				var capacity: int = slidesPerRow*numOfRows;
				if (capacity>=numbOfSlides-1)
					numOfRowsFound = true;
			}
			var slideToProcess:int = slideArrayIndex+2;
			for (var i:int=1;i<=numOfRows;i++){
				xCoordinate = currentX
					+ AS_Constants.WIDTH_PREVIEW_MIDDLE/2
					+ AS_Constants.WIDTH_PREVIEW_SIDES
					+ 2
					+ AS_Constants.WIDTH_MINI_PREVIEW +1
					- locator.scrubber.calculatePreviewPosition();
				var yCoordinate:int = AS_Constants.SCRUBBER_HEIGHT
					+AS_Constants.DISTANCE_PREVIEW_SIDES_TO_SCRUBBER
					+AS_Constants.HEIGHT_PREVIEW_SIDES
					-30-(restHeight+1)*i;
				for (var j:int=1;j<=slidesPerRow;j++){
					if (slideToProcess == slides.length) return;
					tmp = images[slideToProcess];
					tmp.height = restHeight;
					tmp.width = restWidth;
					tmp.x = xCoordinate;
					tmp.y = yCoordinate;
					xCoordinate = xCoordinate + restWidth +1;
					tmp.visible = true;
					slideToProcess+=1;
				}
			}
		}
	}
}